home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / answrbok / 3_14.lha / 3_14 / 3_14.c next >
C/C++ Source or Header  |  1993-08-08  |  7KB  |  340 lines

  1. * Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
  2. * The C++ Answer Book */
  3. * Tony Hansen */
  4. * All rights reserved. */
  5. include <stream.h>
  6. include <string.h>
  7. include <stdlib.h>
  8. ifndef RAND_MAX
  9.  define RAND_MAX 32767
  10. endif
  11. include <ctype.h>
  12.  
  13. nt no_of_errors;
  14.  
  15. ouble error(char *s)
  16.  
  17.    cerr << "error: " << s << "\n";
  18.    no_of_errors++;
  19.    return 1;
  20.  
  21.  
  22. include "3_14b.c"    // d_f_va, maxargs, variable, interp_func, struct name
  23.  
  24. onst TBLSZ = 23;
  25. ame *table[TBLSZ];
  26.  
  27. nt lookhash(char *p)
  28.  
  29.    int ii = 0;
  30.    while (*p) ii = ii << 1 ^ *p++;
  31.    if (ii < 0) ii = -ii;
  32.    return ii % TBLSZ;
  33.  
  34.  
  35. ame *look(char *p, int ins=0)
  36.  
  37.    int ii = lookhash(p);
  38.    
  39.    for (name *n = table[ii]; n; n=n->next)
  40. if (strcmp(p, n->string) == 0)
  41.     return n;
  42.    
  43.    if (ins == 0) error("name not found");
  44.    
  45.    name *nn = new name;
  46.    nn->string = new char[strlen(p)+1];
  47.    strcpy(nn->string, p);
  48.    nn->next = table[ii];
  49. n->nargs = variable;    // #include "3_13c.c"        /* EXPAND4 */
  50.    nn->value = 1;
  51.    table[ii] = nn;
  52.    return nn;
  53.  
  54.  
  55. nline name *insert(char *s) { return look(s, 1); }
  56.  
  57. include "3_14a.c"        // enum token_value { NAME, ... };
  58.  
  59. include "3_14d1.c"        // double *curfuncargs = 0;
  60.  
  61. oken_value curr_tok;
  62. ouble number_value;
  63. onst int namesize = 100;
  64. har name_string[namesize];
  65. oken_value get_token();
  66. ouble expr(), term(), prim();
  67.  
  68. ouble expr()
  69.  
  70. /cerr << "expr()\n";        /* DELETE */
  71.    double left = term();
  72.    for (;;)
  73. {
  74. switch (curr_tok)
  75.     {
  76.     case PLUS: get_token();
  77.         left += term();
  78.     break;
  79.  
  80.     case MINUS: get_token();
  81.         left -= term();
  82.     break;
  83.  
  84.     default:
  85.         return left;
  86.     }
  87. }
  88.  
  89.  
  90. ouble term()
  91.  
  92. /cerr << "term()\n";        /* DELETE */
  93.    double left = prim();
  94.    for (;;)
  95. {
  96. switch (curr_tok) 
  97.     {
  98.     case MUL: get_token();
  99.         left *= prim();
  100.     break;
  101.  
  102.     case DIV:
  103.         get_token();
  104.     double d = prim();
  105.     if (d == 0) return error("divide by 0");
  106.     left /= d;
  107.     break;
  108.  
  109.     default:
  110.         return left;
  111.     }
  112. }
  113.  
  114.  
  115. include "3_14c2.c"    // char *get_funcdefn()
  116. include "3_14e.c"    // double interpfunc(double*, char*)
  117.  
  118. ouble prim()
  119.  
  120. /cerr << "prim(): curr_tok = " << chr(curr_tok) << "\n";        /* DELETE */
  121.    switch (curr_tok) 
  122. {
  123. case NUMBER:
  124. /cerr << "prim(): case NUMBER:\n";        /* DELETE */
  125.     get_token();
  126.     return number_value;
  127.  
  128. include "3_14d2.c"    // case DOL:
  129.  
  130. case NAME:
  131. /cerr << "prim(): case NAME:\n";        /* DELETE */
  132.     get_token();
  133. /cerr << "prim(): curr_tok = " << chr(curr_tok) << "\n";        /* DELETE */
  134.     if (curr_tok == ASSIGN)    // same as before
  135.     {
  136. /cerr << "prim: case NAME: ASSIGN\n";        /* DELETE */
  137.     name *n = insert(name_string);
  138.     get_token();
  139.     n->value = expr();
  140.     return n->value;
  141.     }
  142.  
  143. include "3_14d.c"            // else if (curr_tok == LP)
  144. include "3_14c.c"            // else if (curr_tok == LB)
  145.  
  146.     else            // same as before
  147.     {
  148. /cerr << "prim: case NAME: LOOKUP\n";        /* DELETE */
  149.     name *n = look(name_string);
  150.  
  151.     if (n->nargs == variable)
  152.         return n->value;
  153.  
  154.     else
  155.         return error("( expected");
  156.     }
  157.  
  158. case MINUS:
  159. /cerr << "prim(): case MINUS:\n";        /* DELETE */
  160.     get_token();
  161.     return -prim();
  162.  
  163. case LP:
  164. /cerr << "prim(): case LP:\n";        /* DELETE */
  165.     get_token();
  166.     double e = expr();
  167.     if (curr_tok != RP)
  168.         return error(") expected");
  169.     get_token();
  170.     return e;
  171.  
  172. case END:
  173. /cerr << "prim(): case END:\n";        /* DELETE */
  174.     return 1;
  175.  
  176. default:
  177. /cerr << "prim(): default:\n";        /* DELETE */
  178.     return error("primary expected");
  179. }
  180.  
  181.  
  182. oken_value get_token()
  183.  
  184.    char ch;
  185.    do  {
  186. if (!cin.get(ch)) return curr_tok = END;
  187.    } while (ch != '\n' && isspace(ch));
  188.  
  189.    switch (ch)
  190. {
  191. case ';': case '\n':
  192.     cin >> WS;
  193.     return curr_tok = PRINT;
  194.  
  195. include "3_14a2.c"
  196.  
  197. case '0': case '1': case '2': case '3': case '4':
  198. case '5': case '6': case '7': case '8': case '9':
  199. case '.':
  200.     cin.putback(ch);
  201.     cin >> number_value;
  202.     return curr_tok = NUMBER;
  203.  
  204. default:
  205.     if (isalpha(ch))
  206.     {
  207.     char *p = name_string;
  208.     *p++ = ch;
  209.     while (cin.get(ch) && isalnum(ch) && p < &name_string[namesize-1])
  210.         *p++ = ch;
  211.     if (p == &name_string[namesize])
  212.         while (cin.get(ch) && isalnum(ch))
  213.             ;
  214.     cin.putback(ch);
  215.     *p = 0;
  216.     return curr_tok = NAME;
  217.     }
  218.  
  219.     error("bad token");
  220.     return curr_tok = PRINT;
  221. }
  222.  
  223.  
  224. * declare helper functions for */
  225. * sqrt(), log(), sin() and random() */
  226. include <math.h>
  227.  
  228. / return the square root of e0
  229. tatic double dosqrt(double e[])
  230.  
  231.    return (e[0] < 0) ?
  232. error("sqrt: requires non-negative number") :
  233. sqrt(e[0]);
  234.  
  235.  
  236. / return the natural log of e0
  237. tatic double dolog(double e[])
  238.  
  239.    return (e[0] <= 0) ?
  240. error("log: requires positive number") :
  241. log(e[0]);
  242.  
  243.  
  244. / return the sin of e0
  245. tatic double dosin(double e[])
  246.  
  247.    return sin(e[0]);
  248.  
  249.  
  250. / return a random number between [e0, e1)
  251. tatic double dorandom(double e[])
  252.  
  253.    return rand() / ( (double) RAND_MAX+1) *
  254. (e[1] - e[0]) + e[0];
  255.  
  256.  
  257. tatic double doexp(double e[]) { return exp(e[0]); }
  258. tatic double docos(double e[]) { return cos(e[0]); }
  259. tatic double dotan(double e[]) { return tan(e[0]); }
  260. tatic double doatan(double e[]) { return atan(e[0]); }
  261.  
  262. tatic double dolog10(double e[])
  263.  
  264.    if (e[0] <= 0)    return error("log10: requires non-positive number");
  265.    else    return log10(e[0]);
  266.  
  267.  
  268. tatic double doexp10(double e[])
  269.  
  270.    return pow(10, e[0]);
  271.  
  272.  
  273. tatic double doasin(double e[])
  274.  
  275.    if (e[0] > 1 || e[0] < -1)    return error("asin: requires |x| <= 1.0");
  276.    else            return asin(e[0]);
  277.  
  278.  
  279. tatic double doacos(double e[])
  280.  
  281.    if (e[0] > 1 || e[0] < -1)    return error("acos: requires |x| <= 1.0");
  282.    else            return acos(e[0]);
  283.  
  284.  
  285. tatic double dopow(double e[])
  286.  
  287.    double x = e[0];
  288.    double y = e[1];
  289.    if (x == 0 && y <= 0)    return error("pow: x == 0 requires y > 0");
  290.    else if (x < 0 && y != (double)(int)y)
  291.                    return error("pow: x < 0 requires int y");
  292.    else            return pow(x, y);
  293.  
  294.  
  295. oid insertfunction(char *funcname,
  296.    int nargs, d_f_va funcptr)
  297.  
  298.    name *n = insert(funcname);
  299.    n->nargs = nargs;
  300.    n->funcptr = funcptr;
  301.  
  302.  
  303. nt main(int argc, char **argv)
  304.  
  305.    switch (argc) 
  306. {
  307. case 1: break;
  308. case 2: cin = *new istream(strlen(argv[1]), argv[1]); break;
  309. default: error("too many arguments"); return 1;
  310. }
  311.    
  312.    // initialize known variables
  313.    insert("pi")->value = 3.1415926535897932385;
  314.    insert("e")->value = 2.7182818284590452354;
  315.  
  316.    // initialize known functions
  317.    insertfunction("sqrt", 1, (d_f_va)dosqrt);
  318.    insertfunction("log", 1, (d_f_va)dolog);
  319.    insertfunction("sin", 1, (d_f_va)dosin);
  320.    insertfunction("random", 2, (d_f_va)dorandom);
  321.    insertfunction("exp", 1, (d_f_va)doexp);
  322.    insertfunction("log10", 1, (d_f_va)dolog10);
  323.    insertfunction("pow", 2, (d_f_va)dopow);
  324.    insertfunction("cos", 1, (d_f_va)docos);
  325.    insertfunction("tan", 1, (d_f_va)dotan);
  326.    insertfunction("asin", 1, (d_f_va)doasin);
  327.    insertfunction("acos", 1, (d_f_va)doacos);
  328.    insertfunction("atan", 1, (d_f_va)doatan);
  329.    
  330.    while (cin)
  331. {
  332. get_token();
  333. if (curr_tok == END) break;
  334. if (curr_tok == PRINT) continue;
  335. cout << expr() << "\n";
  336. }
  337.    
  338.    return no_of_errors;
  339.  
  340.